/**
 * Simple LookupTable class
 * @author Thierry & Jin
 *
 */


import java.io.*;
import java.util.*;

public class LUTable {

	// list of value from -> to
	protected TreeMap<Double,Double> table = new TreeMap<Double,Double>();
	
	/**
	 * Main function, add a pair (oldValue;updatedValue)
	 * @param from original value (oldValue)
	 * @param to value we want the original to be converted to (updatedValue)
	 */
	public void add_pair(double from, double to) {
		if ( table.containsKey(from) ) {
			if (table.get(from) != to)
				System.out.println("LUTable.add_pair, same from different to?");
		}
		table.put(from, to);
	}
	
	/**
	 * Size of the table, e.g. number of mappings
	 * @return table size (number of mappings)
	 */
	public int size() {
		return table.size();
	}
	
	/**
	 * Lookup method with linear scaling.
	 * If table size == 1, does nothing, returns input
	 * @param from oldValue we want to update
	 */
	public double lookup(double from) {
		// trivial case, we find from in the table
		if (table.containsKey(from))
			return table.get(from);
		// trivial case 2, table size 1, does nothing
		if (size() == 0) {
			System.out.println("lookup table empty!!!");
			return from;
		}
		if (size() == 1)
			return from;
		// get all keys sorted
		Double bound1 = table.lowerKey(from); // closest smaller
		Double bound2 = table.higherKey(from); // closest bigger
		if (bound1 == null) { // no smaller key
			bound1 = bound2;
			bound2 = table.higherKey(bound1);
			assert(bound2 != null); // because size >= 2
			assert(bound1 != null);
			return from;
		}
		if (bound2 == null) { // no greater key
			bound2 = bound1;
			bound1 = table.lowerKey(bound2);
			assert(bound1 != null); // because size >= 2
			assert(bound2 != null);
			return from;
		}
		// linear scaling
		double bound1_val = table.get(bound1);
		double bound2_val = table.get(bound2);
		if (bound1_val == bound2_val)
			return bound1_val;
		double res = (bound2_val - bound1_val)/ (bound2 - bound1);
		res = res * (from - bound1) + bound1_val;
		return res;
	}

	/**
	 * Add pair taken from a file
	 * File format: # ignored
	 * then valueOld <whitespace> valueUpdated
	 *      valueOld <whitespace> valueUpdated
	 *      etc
	 * @param filename Name of the file
	 */
	public void load_file(String filename){
		File file = new File(filename);
		Scanner scanner = null;
		try {
			scanner = new Scanner(file);
		} catch (FileNotFoundException e) {
			System.out.println("File not found: " + filename);
		}
		try {
			// skip comments
			while(true) {
				if (!scanner.hasNext("#"))
					break;
				scanner.nextLine();
			}
			// get values
			while(true) {
				if (!scanner.hasNextDouble())
					break;
				double from = scanner.nextDouble();
				double to = scanner.nextDouble();
				this.add_pair(from,to);
			}
		} catch (InputMismatchException e) {
			System.out.println("Mismatch exception: " + e);
		}
		scanner.close();
	}
	
	
	/**
	 * Constructor is used for DEBUGGING purposes only
	 */
	/*
	public LUTable()
	{
		add_pair(1,2);
		add_pair(5,10);
		System.out.println(lookup(-.5));
		System.out.println(lookup(3));
		System.out.println(lookup(10));
		// load from file
		load_file("TestLookupLoad.txt");
		System.out.println("size="+size());
		System.out.println(lookup(100));
	}
	*/
}
